package com.cleaningcloud.cld.service.impl;

import com.cleaningcloud.cld.domain.CldAttendance;
import com.cleaningcloud.cld.domain.CldCalendar;
import com.cleaningcloud.cld.domain.CldPayDetails;
import com.cleaningcloud.cld.domain.CldProject;
import com.cleaningcloud.cld.domain.dto.CldAttendanceDto;
import com.cleaningcloud.cld.domain.dto.CldProjectPostDto;
import com.cleaningcloud.cld.domain.model.TableCalendarVo;
import com.cleaningcloud.cld.domain.vo.CldAttendanceVo;
import com.cleaningcloud.cld.domain.vo.CldProjectPostSetVo;
import com.cleaningcloud.cld.mapper.CldAttendanceMapper;
import com.cleaningcloud.cld.mapper.CldCalendarMapper;
import com.cleaningcloud.cld.mapper.CldProjectMapper;
import com.cleaningcloud.cld.mapper.CldProjectPostMapper;
import com.cleaningcloud.cld.service.ICldAttendanceService;
import com.cleaningcloud.cld.service.ICldCalendarService;
import com.cleaningcloud.cld.service.ICldPayDetailsService;
import com.cleaningcloud.cld.utils.AttendanceConversionUtils;
import com.cleaningcloud.common.core.utils.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 考勤打卡Service业务层处理
 *
 * @author cleaningcloud
 * @date 2024-11-08
 */
@Service
public class CldAttendanceServiceImpl implements ICldAttendanceService {
    @Autowired
    private CldAttendanceMapper cldAttendanceMapper;

    @Autowired
    private CldCalendarMapper cldCalendarMapper;

    @Autowired
    private CldProjectMapper cldProjectMapper;

    @Autowired
    private CldProjectPostMapper cldProjectPostMapper;

    @Autowired
    private ICldPayDetailsService cldPayDetailsService;

    @Autowired
    private ICldCalendarService cldCalendarService;


    /**
     * 查询考勤打卡
     *
     * @param attendanceId 考勤打卡主键
     * @return 考勤打卡
     */
    @Override
    public CldAttendanceVo selectCldAttendanceByAttendanceId(Long attendanceId) {
        return cldAttendanceMapper.selectCldAttendanceByAttendanceId(attendanceId);
    }

    /**
     * 查询考勤打卡列表
     *
     * @param cldAttendance 考勤打卡
     * @return 考勤打卡
     */
    @Override
    public List<CldAttendanceVo> selectCldAttendanceList(CldAttendanceDto cldAttendance) {
        return cldAttendanceMapper.selectCldAttendanceList(cldAttendance);
    }

    @Override
    public List<CldAttendanceVo> selectProjectClassificationList(CldAttendanceDto cldAttendanceDto) {
        return cldAttendanceMapper.selectProjectClassificationList(cldAttendanceDto);
    }

    @Override
    public List<CldAttendanceVo> selectAttendanceStatisticsList(CldAttendanceDto cldAttendanceDto) {
        return cldAttendanceMapper.selectAttendanceStatisticsList(cldAttendanceDto);
    }

    /**
     * 新增考勤打卡
     *
     * @param cldAttendance 考勤打卡
     * @return 结果
     */
    @Override
    public int insertCldAttendance(CldAttendance cldAttendance) {
        // 获取是否为节假日
        CldCalendar calendarQuery = new CldCalendar();
        calendarQuery.setCalendarYear(cldAttendance.getAttendanceYear());
        calendarQuery.setCalendayMonth(cldAttendance.getAttendanceMonth());
        calendarQuery.setCalendayDay(cldAttendance.getAttendanceDay());
        List<CldCalendar> calendarList = cldCalendarMapper.selectCldCalendarList(calendarQuery);
        if (!calendarList.isEmpty()) {
            cldAttendance.setIsHoliday(calendarList.get(0).getCalendayType().equals("2") ? 1L : 0L);
        }
        return cldAttendanceMapper.insertCldAttendance(cldAttendance);
    }

    /**
     * 修改考勤打卡
     *
     * @param cldAttendance 考勤打卡
     * @return 结果
     */
    @Override
    @Transactional
    public int updateCldAttendance(CldAttendance cldAttendance) {
        CldAttendanceVo attendance = cldAttendanceMapper.selectCldAttendanceByAttendanceId(cldAttendance.getAttendanceId());
        // 本日需打卡 比对 已打卡 通过则修改为有效考勤
        boolean flag = true;
        // 是否为请假考勤
        if (attendance.getIsLeave() == 1) {
            flag = false;
            AttendanceConversionUtils.AttendanceConversion(attendance);
            if (attendance.getLeaveHours().doubleValue() < 8) {
                // 至少打一次卡
                if (attendance.getEchoGoToWorkTime1() != null && cldAttendance.getGoToWorkTime1() != null) {
                    flag = true;
                } else if (attendance.getEchoGoOffWorkTime1() != null && cldAttendance.getGoOffWorkTime1() != null) {
                    flag = true;
                } else if (attendance.getEchoGoToWorkTime2() != null && cldAttendance.getGoToWorkTime2() != null) {
                    flag = true;
                } else if (attendance.getEchoGoOffWorkTime2() != null && cldAttendance.getGoOffWorkTime2() != null) {
                    flag = true;
                } else if (attendance.getEchoGoToWorkTime3() != null && cldAttendance.getGoToWorkTime3() != null) {
                    flag = true;
                } else if (attendance.getEchoGoOffWorkTime3() != null && cldAttendance.getGoOffWorkTime3() != null) {
                    flag = true;
                }
            }
        } else {
            // 正常考勤班次
            if(attendance.getIsSpecial() == null || attendance.getIsSpecial() == 0){
                if (attendance.getEchoGoToWorkTime1() != null && cldAttendance.getGoToWorkTime1() == null) {
                    flag = false;
                }
                if (attendance.getEchoGoOffWorkTime1() != null && cldAttendance.getGoOffWorkTime1() == null) {
                    flag = false;
                }
                if (attendance.getEchoGoToWorkTime2() != null && cldAttendance.getGoToWorkTime2() == null) {
                    flag = false;
                }
                if (attendance.getEchoGoOffWorkTime2() != null && cldAttendance.getGoOffWorkTime2() == null) {
                    flag = false;
                }
                if (attendance.getEchoGoToWorkTime3() != null && cldAttendance.getGoToWorkTime3() == null) {
                    flag = false;
                }
                if (attendance.getEchoGoOffWorkTime3() != null && cldAttendance.getGoOffWorkTime3() == null) {
                    flag = false;
                }
            }else{
                // 任何一个班次不为空 这满足薪资发放
                flag = false;
                if(
                        (cldAttendance.getGoToWorkTime1() != null && cldAttendance.getGoOffWorkTime1() != null) ||
                                (cldAttendance.getGoToWorkTime2() != null && cldAttendance.getGoOffWorkTime2() != null) ||
                                (cldAttendance.getGoToWorkTime3() != null && cldAttendance.getGoOffWorkTime3() != null)
                ){
                    flag = true;
                }
            }
        }
        // 如已是有效考勤 则不生成薪酬明细
        if (flag && attendance.getIsEffective() == 0 && attendance.getIsRest() == 0) {
            cldAttendance.setIsEffective(1L);
            cldAttendance.setIsPay(1L);
            LocalDate localDate = LocalDate.now();
            // 获取当月天数
            int daysInMonth = localDate.lengthOfMonth();
            // 生成薪酬明细
            CldProjectPostDto postQuery = new CldProjectPostDto();
            postQuery.setProjectId(attendance.getProjectId());
            postQuery.setStaffId(attendance.getStaffId());
            postQuery.setIsMasterDuits(1L);
            List<CldProjectPostSetVo> postSetVoList = cldProjectPostMapper.selectCldProjectPostList(postQuery);
            if (!postSetVoList.isEmpty()) {
                BigDecimal dailyAverage = null;
                CldProjectPostSetVo projectPostSetVo = postSetVoList.get(0);
                // 计算日平均工资
                if (projectPostSetVo.getPostWages() == null) {
                    projectPostSetVo.setPostWages(new BigDecimal("1900"));
                }
                // 如为通班 月天数 / 2
                BigDecimal decimalDaysInmonth = null;
                if(attendance.getIsClass() != null && attendance.getIsClass() == 1){
                    decimalDaysInmonth = BigDecimal.valueOf(daysInMonth).divide(BigDecimal.valueOf(2)) ;
                    dailyAverage = projectPostSetVo.getPostWages().divide(decimalDaysInmonth, 2, RoundingMode.HALF_UP);
                    //当月最后一天
                    if (decimalDaysInmonth.compareTo(BigDecimal.valueOf(localDate.getDayOfMonth()).divide(BigDecimal.valueOf(2))) == 0) {
                        if(daysInMonth % 2 == 0){
                            dailyAverage = projectPostSetVo.getPostWages().subtract(dailyAverage.multiply(decimalDaysInmonth.subtract(BigDecimal.valueOf(1))));
                        }else{
                            dailyAverage = projectPostSetVo.getPostWages().subtract(dailyAverage.multiply(decimalDaysInmonth.subtract(BigDecimal.valueOf(0.5))));
                        }
                    }
                }else{
                    dailyAverage = projectPostSetVo.getPostWages().divide(BigDecimal.valueOf(daysInMonth), 2, RoundingMode.HALF_UP);
                    //当月最后一天
                    if (daysInMonth == localDate.getDayOfMonth()) {
                        dailyAverage = projectPostSetVo.getPostWages().subtract(dailyAverage.multiply(BigDecimal.valueOf(daysInMonth - 1)));
                    }
                }

                // 如存在请假
                if(attendance.getIsLeave() == 1L){
                    CldPayDetails cldPayDetails = AttendanceConversionUtils.LeaveSalaryCalculate(attendance, projectPostSetVo);
                    cldPayDetailsService.insertCldPayDetails(cldPayDetails);
                }

                // 薪酬明细
                CldPayDetails cldPayDetails = new CldPayDetails();
                cldPayDetails.setBusinessId(attendance.getAttendanceId());
                cldPayDetails.setProjectId(attendance.getProjectId());
                cldPayDetails.setStaffId(attendance.getStaffId());
                cldPayDetails.setProjectPostId(projectPostSetVo.getProjectPostName());
                cldPayDetails.setPayType(1L);
                cldPayDetails.setMoney(dailyAverage);
                cldPayDetails.setIsAlgorithm(1L);
                cldPayDetails.setYear(cldAttendance.getAttendanceYear());
                cldPayDetails.setMonth(cldAttendance.getAttendanceMonth());
                cldPayDetails.setDay(cldAttendance.getAttendanceDay());
                // 如为补卡操作  生成补卡那天薪酬明细
                if (cldAttendance.getIsReplace() != null && cldAttendance.getIsReplace() == 1) {
                    cldPayDetails.setRemark("补卡");
                } else {
                    cldPayDetails.setRemark("考勤打卡薪酬");
                }
                cldPayDetailsService.insertCldPayDetails(cldPayDetails);
            }
        }
        return cldAttendanceMapper.updateCldAttendance(cldAttendance);
    }

    @Override
    @Transactional
    public int batchUpdateAttendance(List<CldAttendance> cldAttendances) {
        for (CldAttendance cldAttendance : cldAttendances) {
            updateCldAttendance(cldAttendance);
        }
        return 1;
    }

    /**
     * 批量删除考勤打卡
     *
     * @param attendanceIds 需要删除的考勤打卡主键
     * @return 结果
     */
    @Override
    public int deleteCldAttendanceByAttendanceIds(Long[] attendanceIds) {
        return cldAttendanceMapper.deleteCldAttendanceByAttendanceIds(attendanceIds);
    }

    /**
     * 删除考勤打卡信息
     *
     * @param attendanceId 考勤打卡主键
     * @return 结果
     */
    @Override
    public int deleteCldAttendanceByAttendanceId(Long attendanceId) {
        return cldAttendanceMapper.deleteCldAttendanceByAttendanceId(attendanceId);
    }


    @Override
    public Map<String, Object> getTableCalendarList(CldAttendanceDto cldAttendanceDto) {
        // 查询项目信息
        CldProject cldProject = cldProjectMapper.selectCldProjectByProjectId(cldAttendanceDto.getProjectId());
        if (cldProject == null) {
            throw new RuntimeException("查询项目信息失败！");
        }
        Map<String, Object> resultMap = new HashMap<>();
        resultMap.put("projectName", cldProject.getProjectName());
        resultMap.put("projectStatus", cldProject.getProjectStatus());
        // 查询当月日历信息
        CldCalendar calendarQuery = new CldCalendar();
        calendarQuery.setCalendarYear(Math.toIntExact(cldAttendanceDto.getAttendanceYear()));
        calendarQuery.setCalendayMonth(Math.toIntExact(cldAttendanceDto.getAttendanceMonth()));
        List<CldCalendar> calendarList = cldCalendarService.selectCldCalendarList(calendarQuery);
        resultMap.put("calendarList", calendarList);
        List<TableCalendarVo> tableCalendarVoList = new ArrayList<>();
        
        if(cldProject.getProjectStatus() == 2){
            // 查询项目岗位
            CldProjectPostDto projectPostQuery = new CldProjectPostDto();
            projectPostQuery.setProjectId(cldProject.getProjectId());
            projectPostQuery.setIsMasterDuits(1L);
            List<CldProjectPostSetVo> postVoList = cldProjectPostMapper.selectCldProjectPostList(projectPostQuery);
            for (CldProjectPostSetVo projectPost : postVoList) {
                if (projectPost.getStaffId() != null) {
                    TableCalendarVo tableCalendarVo = new TableCalendarVo();
                    tableCalendarVo.setStaffName(projectPost.getStaffName());
                    tableCalendarVo.setProjectPostName(projectPost.getProjectPostName());
                    tableCalendarVo.setProjectPostNo(projectPost.getProjectPostNo());
                    if (projectPost.getGroupName() != null) {
                        tableCalendarVo.setGroupName(projectPost.getGroupName().toString());
                    }
                    tableCalendarVo.setStaffId(projectPost.getStaffId());
                    // 根据项目岗位人员查询考勤记录
                    CldAttendanceDto attendanceQuery = new CldAttendanceDto();
                    attendanceQuery.setProjectId(cldProject.getProjectId());
                    attendanceQuery.setStaffId(projectPost.getStaffId());
                    attendanceQuery.setAttendanceYear(cldAttendanceDto.getAttendanceYear());
                    attendanceQuery.setAttendanceMonth(cldAttendanceDto.getAttendanceMonth());
                    Map<String, Object> attendanceMap = new HashMap<>();
                    List<CldAttendanceVo> attendanceList = cldAttendanceMapper.selectCldAttendanceList(attendanceQuery);
                    int count = (int) attendanceList.stream().filter(n -> n.getIsEffective() == 1).count();
                    tableCalendarVo.setAttendanceCount(count);
                    for (CldAttendanceVo attendance : attendanceList) {
                        AttendanceConversionUtils.AttendanceConversion(attendance);
                        attendanceMap.put(DateUtils.parseDateToStr("yyyy-MM-dd", attendance.getAttendanceDate()), attendance);
                    }
                    tableCalendarVo.setDayData(attendanceMap);
                    tableCalendarVoList.add(tableCalendarVo);
                }
            }
        }else{
            CldAttendanceDto attendanceQuery = new CldAttendanceDto();
            attendanceQuery.setProjectId(cldProject.getProjectId());
            attendanceQuery.setAttendanceYear(cldAttendanceDto.getAttendanceYear());
            attendanceQuery.setAttendanceMonth(cldAttendanceDto.getAttendanceMonth());
            List<CldAttendanceVo> attendanceList = cldAttendanceMapper.selectCldAttendanceList(attendanceQuery);
            for (CldAttendanceVo cldAttendanceVo : attendanceList) {
                if(tableCalendarVoList.stream().noneMatch(n -> n.getStaffId().equals(cldAttendanceVo.getStaffId()))){
                    TableCalendarVo tableCalendarVo = new TableCalendarVo();
                    tableCalendarVo.setStaffName(cldAttendanceVo.getStaffName());
                    tableCalendarVo.setStaffId(cldAttendanceVo.getStaffId());
                    tableCalendarVoList.add(tableCalendarVo);
                }
            }
            for (TableCalendarVo tableCalendarVo : tableCalendarVoList) {
                // 根据项目岗位人员查询考勤记录
                attendanceQuery = new CldAttendanceDto();
                attendanceQuery.setProjectId(cldProject.getProjectId());
                attendanceQuery.setStaffId(tableCalendarVo.getStaffId());
                attendanceQuery.setAttendanceYear(cldAttendanceDto.getAttendanceYear());
                attendanceQuery.setAttendanceMonth(cldAttendanceDto.getAttendanceMonth());
                Map<String, Object> attendanceMap = new HashMap<>();
                attendanceList = cldAttendanceMapper.selectCldAttendanceList(attendanceQuery);
                int count = (int) attendanceList.stream().filter(n -> n.getIsEffective() == 1).count();
                tableCalendarVo.setAttendanceCount(count);
                for (CldAttendanceVo attendance : attendanceList) {
                    AttendanceConversionUtils.AttendanceConversion(attendance);
                    attendanceMap.put(DateUtils.parseDateToStr("yyyy-MM-dd", attendance.getAttendanceDate()), attendance);
                }
                tableCalendarVo.setDayData(attendanceMap);
            }
        }
        resultMap.put("staffList", tableCalendarVoList);
        return resultMap;
    }

    @Override
    public Map<String, Object> getCalendarByStaffId(CldAttendanceDto cldAttendanceDto) {
        Map<String, Object> resultMap = new HashMap<>();
        // 根据项目岗位人员查询考勤记录
        CldAttendanceDto attendanceQuery = new CldAttendanceDto();
        attendanceQuery.setProjectId(cldAttendanceDto.getProjectId());
        attendanceQuery.setStaffId(cldAttendanceDto.getStaffId());
        attendanceQuery.setAttendanceYear(cldAttendanceDto.getAttendanceYear());
        attendanceQuery.setAttendanceMonth(cldAttendanceDto.getAttendanceMonth());
        List<CldAttendanceVo> attendanceList = cldAttendanceMapper.selectCldAttendanceList(attendanceQuery);
        for (CldAttendanceVo attendanceVo : attendanceList) {
            AttendanceConversionUtils.AttendanceConversion(attendanceVo);
            resultMap.put("projectPostName", attendanceVo.getProjectPostName());
            resultMap.put("staffName", attendanceVo.getStaffName());
            resultMap.put(DateUtils.parseDateToStr("yyyy-MM-dd", attendanceVo.getAttendanceDate()), attendanceVo);
        }
        return resultMap;
    }
}
